package com.stone.design.mode.chain;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 使用方法：validatorManager.getHandler().filter(t, transferDTO, type); 这里直接通过
 * validatorManager调用第一个节点的filter方法即可
 * 参考：https://blog.csdn.net/promisessh/article/details/110098683?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
 *
 * @author Mr_wenpan@163.com 2021/3/13 1:22 下午
 */
@Data
@Component
public class ValidatorManager {

    @Autowired
    private ApplicationContext context;
    /**
     * 责任链上的第一个节点
     */
    private ValidatorHandler<?, ?> handler;
    /**
     * 存放所有的责任链上的节点
     */
    private List<ValidatorHandler<?, ?>> handlerList = new LinkedList<>();

    /**
     * 初始化validator，在容器启动注入完成该bean时候就完成组装链条的工作，要使用该责任链只需要：ValidatorManager.getHandler.filter(xx,xx);即可
     */
    @PostConstruct
    public void validatorInit() {
        // 获取所有的ValidatorHandler节点并组装成链条
        Map<String, ValidatorHandler> validatorMap = context.getBeansOfType(ValidatorHandler.class);
        validatorMap.forEach((k, v) -> handlerList.add(v));

        // 排序
        handlerList.sort(Comparator.comparing(ValidatorHandler::getOrder));

        // 将处理器串成链表
        for (int i = 1; i < handlerList.size(); i++) {
            // 当前处理器
            ValidatorHandler<?, ?> currentHandler = handlerList.get(i - 1);
            // 下一个处理器
            ValidatorHandler nextHandler = handlerList.get(i);
            // 将处理器串成链表
            currentHandler.setNextHandler(nextHandler);
        }

        handler = handlerList.get(0);
    }

    /**
     * 这里获取到第责任链上的起点节点，调用该节点的filter方法即可按照链条顺序执行节点了
     *
     * @return ValidatorHandler
     * @author Mr_wenpan@163.com 2021/3/13 1:44 下午
     */
    public ValidatorHandler getHandler() {
        return handler;
    }

}